package com.pbdatabase.core.api;

import com.pbdatabase.core.coordinator.LoadDistributor;
import com.pbdatabase.core.main.PropertyManager;
import com.pbdatabase.core.query.DefinitionQueryHandler;
import com.pbdatabase.core.query.ManipulationQueryHandler;
import org.apache.log4j.Logger;

import javax.servlet.ServletContext;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

@Path("/q")
public class QueryInterface {
	private static Logger _logger = Logger.getLogger(QueryInterface.class);

	@javax.ws.rs.core.Context
	ServletContext context;

	@Path("create")
	@PUT
	@Produces(MediaType.APPLICATION_JSON)
	@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
	public void create(@QueryParam("name") String name,
					   @QueryParam("definition") String definition,
					   @QueryParam("field") String field) {
		try {
			// Create table
			DefinitionQueryHandler dqh = new DefinitionQueryHandler();
			dqh.create(name, definition, field);
			_logger.info("Creating table");

			// Create it on other nodes (create happens on all nodes, insert / select happens selectively)
			String[] urls = PropertyManager.getInstance().getNodes();
			for (String nodeUrl : urls) {
				URL url = new URL(nodeUrl + "/q/create?name=" + name + "&definition=" + definition + "&field=" + field);
				HttpURLConnection conn = (HttpURLConnection) url.openConnection();
				conn.setRequestMethod("PUT");
				conn.setRequestProperty("Accept", "application/json");

				if (conn.getResponseCode() != 200) {
					throw new RuntimeException("Failed : HTTP error code : " + conn.getResponseCode());
				}
				BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
				String output;
				while ((output = br.readLine()) != null) {
					_logger.debug(output);
				}
				conn.disconnect();
			}
		} catch (Exception ex) {
			_logger.error("Issue with create", ex);
		}
	}

	@Path("insert")
	@PUT
	@Produces(MediaType.APPLICATION_JSON)
	@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
	public void insert(@FormParam("name") String name,
					   @FormParam("message") Object message,
					   @FormParam("value") String value) {
		try {
			// Reject request if not for this server
			int serverHash = LoadDistributor.getServerhash(value);
			int thishash = Integer.parseInt(PropertyManager.getInstance().getThisNodeHash());
			if (serverHash != thishash)
				return;

			// Insert record
			_logger.info("Inserting record");
			ManipulationQueryHandler mqh = new ManipulationQueryHandler();
			mqh.insert(name, message, value);
		} catch (Exception ex) {
			_logger.error("Issue with create", ex);
		}
	}

	@Path("select")
	@GET
	@Produces(MediaType.APPLICATION_JSON)
	@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
	public void select(@FormParam("name") String name,
					   @FormParam("value") String value) {
		try {
			// Reject request if not for this server
			int serverHash = LoadDistributor.getServerhash(value);
			int thishash = Integer.parseInt(PropertyManager.getInstance().getThisNodeHash());
			if (serverHash != thishash)
				return;

			// Select record
			_logger.info("Selecting record");
			ManipulationQueryHandler mqh = new ManipulationQueryHandler();
			mqh.select(name, value);
		} catch (Exception ex) {
			_logger.error("Issue with create", ex);
		}
	}
}
